www.gusucode.com > VC++ 编写软件自动升级服务源代码 > VC++ 编写软件自动升级服务源代码/gusucode/updater_src0.8.1.6/CopyFile.cpp
/******************************************************************** created: 2005/03/24 created: 24:3:2005 13:27 filename: CopyFile.cpp file path: Updater file base: CopyFile file ext: cpp author: Geert van Horrik purpose: *********************************************************************/ //********************************************************************* // INCLUDES //********************************************************************* #include "stdafx.h" #include "Updater.h" #include "CopyFile.h" //********************************************************************* // MESSAGE MAP //********************************************************************* BEGIN_MESSAGE_MAP(CCopyFile, CWinThread) ON_THREAD_MESSAGE(WMU_COPY_START, OnStartCopy) END_MESSAGE_MAP() //********************************************************************* // CONSTRUCTOR & DESTRUCTOR //********************************************************************* IMPLEMENT_DYNCREATE(CCopyFile, CWinThread) //===================================================================== CCopyFile::CCopyFile() { } //===================================================================== CCopyFile::~CCopyFile() { } //********************************************************************* // PUBLIC FUNCTIONS //********************************************************************* BOOL CCopyFile::InitInstance() { // Log CLog::Instance()->Log("CCopyFile::InitInstance"); return TRUE; } //===================================================================== int CCopyFile::ExitInstance() { // Log CLog::Instance()->Log("CCopyFile::ExitInstance"); // Delete objects if (m_pOriginalFile) delete m_pOriginalFile; if (m_pNewFile) delete m_pNewFile; // Auto delete m_bAutoDelete = TRUE; // Call original function return CWinThread::ExitInstance(); } //===================================================================== void CCopyFile::SetParent(CWinThread * pParentThread) { // Set parent m_pParent = pParentThread; } //===================================================================== void CCopyFile::StartFileCopy(CFile * pOriginalFile, CString sNewFile, bool bSkipIfExists) { // Set default values m_pNewFile = NULL; m_pOriginalFile = NULL; CPath * pPath = CPath::Instance(); // Check if file exists if (PathFileExists(sNewFile)) { // Should we fail now? if (bSkipIfExists) { // Don't really fail, send ready message PostMessageToParent(WMU_COPY_COMPLETE, 0, 0); // Exit this thread PostThreadMessage(WM_QUIT, 0, 0); return; } } // Be sure the directory exists if (!PathFileExists(pPath->ExtractFilePath(sNewFile))) { // It does not exist, create it CFunctions::Instance()->CreateFolder(pPath->ExtractFilePath(sNewFile)); } // Set options m_pOriginalFile = pOriginalFile; m_bSkipIfExists = bSkipIfExists; // Check if file already exists if (PathFileExists(sNewFile)) { // Set file attributes to normal so we are sure we are not dealing with a read-only file SetFileAttributes(sNewFile, FILE_ATTRIBUTE_NORMAL); } try { // Create file m_pNewFile = new CFile(sNewFile, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary); } catch (CFileException * pEx) { #if defined _DEBUG || defined _BETA pEx->ReportError(); #endif // Delete exception object pEx->Delete(); // Send error report PostMessageToParent(WMU_ERROR, ERROR_COPYFILE, 0); // Exit return; } // Send yourself message to start PostThreadMessage(WMU_COPY_START, 0, 0); } //===================================================================== void CCopyFile::StartFileCopy(CString sOriginalFile, CString sNewFile, bool bSkipIfExists) { USES_CONVERSION; // Set default values m_pNewFile = NULL; m_pOriginalFile = NULL; CPath * pPath = CPath::Instance(); // Check if file exists if (PathFileExists(sNewFile)) { // Should we fail now? if (bSkipIfExists) { // Don't really fail, send ready message PostMessageToParent(WMU_COPY_COMPLETE, 0, 0); // Exit this thread PostThreadMessage(WM_QUIT, 0, 0); return; } } // Be sure the directory exists if (!PathFileExists(pPath->ExtractFilePath(sNewFile))) { // It does not exist, create it CFunctions::Instance()->CreateFolder(pPath->ExtractFilePath(sNewFile)); } // Check if file exists if (!PathFileExists(sOriginalFile)) { // Send error report PostMessageToParent(WMU_ERROR, ERROR_FILENOTFOUND, 0); // Exit return; } // Get original file try { m_pOriginalFile = new CFile(sOriginalFile, CFile::shareDenyNone | CFile::modeRead | CFile::typeBinary); } catch (CFileException * pEx) { #if defined _DEBUG || defined _BETA pEx->ReportError(); #endif // Delete exception object pEx->Delete(); // Send error report PostMessageToParent(WMU_ERROR, ERROR_COPYFILE, 0); // Exit return; } // Be sure the folder exists if (!CreateFolder(W2A(ExtractFilePath(sNewFile)))) { // Send error report PostMessageToParent(WMU_ERROR, ERROR_WRITEFILE, 0); // Exit return; } // Check if file already exists if (PathFileExists(sNewFile)) { // Set file attributes to normal so we are sure we are not dealing with a read-only file SetFileAttributes(sNewFile, FILE_ATTRIBUTE_NORMAL); } try { // Create file m_pNewFile = new CFile(sNewFile, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary); } catch (CFileException * pEx) { #if defined _DEBUG || defined _BETA pEx->ReportError(); #endif // Delete exception object pEx->Delete(); // Send error report PostMessageToParent(WMU_ERROR, ERROR_COPYFILE, 0); // Exit return; } // Set options m_bSkipIfExists = bSkipIfExists; // Send yourself message to start PostThreadMessage(WMU_COPY_START, 0, 0); } //********************************************************************* // PRIVATE FUNCTIONS //********************************************************************* void CCopyFile::Copy(CFile * pOriginalFile, CFile * pNewFile, bool bSkipIfExists) { // Declare variables char szBuffer[BUFFER_COPYFILE]; int iFileBytes, iFileBytesCopied, iBytesRead; int iPreviousFileProgress = -1, iPreviousTotalProgress = -1; CFileStatus fileStatusLocation, fileStatusDestination; CString sNewFilePath; // Can we start? if (pNewFile == NULL) { // Send error message PostMessageToParent(WMU_ERROR, ERROR_COPYFILE, 0); // Exit this thread PostThreadMessage(WM_QUIT, 0, 0); } // Use try to catch errors try { // Get file date/time of original file pOriginalFile->GetStatus(fileStatusLocation); // Seek to end iFileBytes = static_cast<int>(pOriginalFile->SeekToEnd()); // Move cursor back to start byte pOriginalFile->Seek(0, CFile::begin); // Set bytes copied (is needed if resume is enabled) iFileBytesCopied = 0; // Move cursor of write file to end of file pNewFile->SeekToEnd(); // Read from file while (iBytesRead = pOriginalFile->Read(szBuffer, BUFFER_COPYFILE)) { // Write actual data into file pNewFile->Write(szBuffer, iBytesRead); // Update copied bytes iFileBytesCopied += iBytesRead; // Send copy status to parent SendCopyStatus(iFileBytesCopied, iFileBytes); } // Get new file path sNewFilePath = pNewFile->GetFilePath(); // Set file date/time of original file pNewFile->GetStatus(fileStatusDestination); pNewFile->Close(); // Copy ended, close file pOriginalFile->Close(); } // If there where any errors, catch them catch (CException * pEx) { #ifdef _DEBUG pEx->ReportError(); #endif // Delete exception object to prevent leaks pEx->Delete(); // Post error PostMessageToParent(WMU_ERROR, ERROR_COPYFILE, 0); } // Try to set file status try { fileStatusDestination.m_atime = fileStatusLocation.m_atime; fileStatusDestination.m_ctime = fileStatusLocation.m_ctime; fileStatusDestination.m_mtime = fileStatusLocation.m_mtime; CFile::SetStatus(sNewFilePath, fileStatusDestination); } catch (CException * pEx) { // Not important pEx->Delete(); } } //===================================================================== CString CCopyFile::ExtractFilePath(CString sFilename) { // Declare variables int iPos; // Now search for the last backslash for (int i = sFilename.GetLength(); i > 0; i--) { iPos = sFilename.Find('\\', sFilename.GetLength()-(sFilename.GetLength()-i)); // If we found them, delete last piece if (iPos != -1) { sFilename.Delete(iPos, sFilename.GetLength()-i); return sFilename; } } // If we not found, we are already dealing with path return sFilename; } //===================================================================== bool CCopyFile::CreateFolder(CString sFolder) { // Declare variables DWORD dwAttrib = GetFileAttributes(sFolder); CString sTemp; // Is folder already existing? if (PathFileExists(sFolder)) return true; // Recursively create from the top down int iPos = sFolder.ReverseFind(_T('\\')); if (iPos != -1) { // The parent is a dir, not a drive sTemp = sFolder; sTemp.Delete(iPos, sFolder.GetLength() - iPos); // if can't create parent if (!CreateFolder(sTemp)) { return false; } // Check if last character is a backslash if (sTemp.GetAt(sTemp.GetLength() - 1) == _T('\\')) return true; // Check if path exists if (PathFileExists(sFolder)) return true; // Try to create directory if (!::CreateDirectory(sFolder, NULL)) return false; } // If we get here, function is successful return true; } //===================================================================== void CCopyFile::SendCopyStatus(int iBytesCopied, int iTotalBytes) { // Declare variables int iPercentageCompleted, iCurrentActionPoints, iTemp; // Calculate current percentage completed if (iBytesCopied > INT_MAX / 100) { // Size is getting too large, go a few steps back iTemp = iBytesCopied / 10000; // Calculate it iPercentageCompleted = iTemp / (iTotalBytes / 1000000); } else { // Calculate percentage on a normal way iPercentageCompleted = (iBytesCopied * 100) / iTotalBytes; } // Because sometimes we are not very accurate if (iPercentageCompleted > 100) { iPercentageCompleted = 100; } // Calculate current actionpoints completed iCurrentActionPoints = (iPercentageCompleted * m_iActionPoints) / 100; // Send information to parent if (m_pParent && (m_iCurrentActionPoints != iCurrentActionPoints)) { m_iCurrentActionPoints = iCurrentActionPoints; // Send status PostMessageToParent(WMU_COPY_STATUS, m_iCurrentActionPoints, m_iActionPoints); } } //===================================================================== void CCopyFile::PostMessageToParent(UINT message, WPARAM wParam, LPARAM lParam) { // Check if parent is still valid if (!IsBadReadPtr(m_pParent, sizeof(CWinThread *))) { // Send message m_pParent->PostThreadMessage(message, wParam, lParam); } } //===================================================================== void CCopyFile::OnStartCopy(WPARAM wParam, LPARAM lParam) { // Init action points m_iCurrentActionPoints = 0; // Dangerous code try { // Calculate action points m_iActionPoints = CActionPoints::CalculateActionPoints(static_cast<int>(m_pOriginalFile->SeekToEnd())); // Start the copy process Copy(m_pOriginalFile, m_pNewFile, m_bSkipIfExists); // Send message to parent that we are ready PostMessageToParent(WMU_COPY_COMPLETE, 0, 0); } catch (...) { // Send error message PostMessageToParent(WMU_ERROR, ERROR_COPYFILE, 0); } }